Skip to main content

02 - 上下文腐烂

前置01 篇的五个 token 去向。

本篇回答:为什么"反正窗口有 100 万 token,多塞点没坏处"这个假设不成立,以及它具体以什么形态失效。

本篇会用到的词

意思
大海捞针(needle in a haystack)长上下文的经典测法:把一句话(针)埋进一大段无关文本(草堆)里,问模型那句话说了什么
针-问相似度那句话和提问之间的语义接近程度。相似度高=字面几乎能对上,低=需要推理才能建立联系
干扰项(distractor)和正确答案话题相关、但不是答案的内容。它比纯无关内容更容易把模型带偏
局部连贯草堆本身读起来像一篇正常文章,而不是随机句子拼接
弃权模型明确回答"找不到答案",而不是编一个。它是一种更安全的失败方式

一、被广泛默认、但不成立的那个假设

几乎所有"把东西塞进上下文"的设计背后都有一个隐含假设:模型处理第 10,000 个 token 和处理第 100 个 token 一样可靠。窗口标称多大,就当它均匀好用到多大。

Chroma 在 2025 年 7 月的技术报告里,在 18 个模型上(含 GPT-4.1、Claude 4、Gemini 2.5、Qwen3 系列)做了一组控制变量实验来检验它。做法是:保持任务本身完全不变,只把输入拉长,看表现怎么变。

同一个任务,只改输入长度准确率假设:均匀好用,水平线实测:持续下滑,而且不平滑1K10K50K200K1M输入长度
曲线的形状是示意,报告里的具体数字随模型和任务而异。真正要记住的是两点:它一直在跌,而且跌得不平滑 —— 不存在一个"过了这个长度才开始变差"的干净阈值,也就没法靠"只要不超过 N token 就安全"来设计。

关键结论是一句话:模型并不均匀地使用上下文。表现随输入变长而变得不可靠,即使是检索、复述这类极简任务也一样。

二、三组变量,三个反直觉结论

报告最有价值的部分不是"变长会变差",而是变差的程度取决于什么

2.1 针-问相似度越低,长度惩罚越重

把"针"和问题之间的语义距离拉开(从字面几乎能对上,到需要推理才能建立联系),再分别在不同输入长度上测:

四条线是同一个任务的四种问法,唯一差别是问题和答案的语义接近程度准确率相似度高中等相似度低短输入长输入工程含义:需要模型自己建立联系的任务("根据这些日志判断根因"),对上下文长度远比字面检索敏感。
这解释了一个常见现象:同一个 Agent,做"找出文件里的某个函数"很稳,做"这段代码为什么会挂"到了长上下文就不行了。两者对上下文长度的容忍度根本不在一个量级,不能用前者的表现去推断后者。

2.2 一个干扰项就能拉低表现,而且各不相同

在草堆里放入一个和答案话题相关但不是答案的内容,表现就相对无干扰基线下降。更麻烦的是"干扰项的影响并不均匀"—— 有些干扰项造成的下滑远大于其他。

失败的方式也分家族:报告观察到 GPT 系列的幻觉率最高,"经常给出自信但错误的回答";Claude 系列更倾向于在不确定时弃权,明确说找不到答案。

工程含义:检索召回的条数不是越多越好。多召回的那几条如果是"相关但不是答案",它们正是最有害的那种干扰项。这一条和记忆专题 04 篇第四节的召回预算是同一件事的两个方向。

2.3 草堆越像一篇正常文章,表现越差

这条是最反直觉的:

当草堆保持了逻辑上的连贯时,模型表现更差。把草堆打乱、破坏局部连贯,表现反而稳定提升。

同样的针、同样的长度,只改草堆内部的组织方式连贯的草堆读起来像一篇正常文章上下文之间有语义连接表现更差连贯性本身在跟"针"抢注意力打乱的草堆句子顺序随机局部连贯被破坏表现稳定更好"针"因为格格不入而更突出
不要据此去打乱你的上下文 —— 这条结论的工程价值在别处:它说明模型对上下文的处理受结构影响很深,而不只是受长度影响。同一批 token 换个组织方式,表现就会变;这正是"上下文工程"这个说法成立的根据。

2.4 连最简单的复述任务也会退化

报告里还有一个几乎剥离了所有难度的任务:给模型一串重复的词,其中插入一个不同的词,让它把序列复述一遍。随着长度增加,所有模型的表现都持续下降;且插入位置越靠前,位置判断越准。

这一条封住了最后一个退路:不能把腐烂归因于"任务太难"或"检索没做好"。在最小条件下,长度本身就是一个独立的负面变量

三、位置效应:中间最容易被丢

比 Chroma 报告早两年的《Lost in the Middle》(arXiv 2307.03172,2023-07 发布、2023-11 修订)给出了另一个维度的证据:把相关信息放在上下文不同位置,表现会显著变化。

横轴是"相关信息埋在上下文的第几成位置",纵轴是准确率准确率开头:好中间:显著变差结尾:好论文原话的要点:即使是专门为长上下文设计的模型,也表现出同样的形状 —— 这不是某一代模型的缺陷。
这条 U 型曲线是 06 篇排布建议的依据之一:最重要的约束放在系统提示词(开头),当前这一轮真正要处理的东西放在最后(结尾),中间留给可以被丢的历史。

四、为什么会这样

Anthropic 在《Effective context engineering for AI agents》里给了一个可操作的解释框架,两条:

  1. 架构层面:Transformer 里每个 token 都要和其余所有 token 建立关系,规模是 n²。上下文变长,同样的注意力要摊到更多的成对关系上
  2. 训练分布层面:模型见过的长序列数据比短序列少得多,"对上下文范围的依赖关系,模型经验更少、专门的参数也更少"

由此提出的类比是注意力预算:模型的注意力像人的工作记忆一样是有限资源,每多放一个 token,就从这份预算里划走一点。

这个类比的实用之处在于它给出的是梯度而不是悬崖:不存在一个"到这里为止都安全"的阈值,只有一条持续变差的曲线。所以上下文管理不是"窗口快满了才要做的事",而是从第一轮就该做的事。

五、怎么在自己的系统上确认

上面的结论都来自公开实验,但你的任务和数据不一样。一个两小时能跑完的自测:

# 思路:固定任务与答案,只往上下文里灌无关内容,看成功率什么时候开始掉。
# 关键是「灌的内容必须真的无关」—— 灌相关内容测出来的是干扰项效应,不是长度效应。
PADDINGS = [0, 10_000, 30_000, 60_000, 120_000] # 额外灌入的 token 量

for pad in PADDINGS:
for case in GOLDEN_CASES: # 20 到 50 条有确定答案的真实任务
ctx = build_context(case)
# 灌在中间:既不占开头也不占结尾,符合真实 Agent 里历史累积的位置
ctx = inject_filler(ctx, tokens=pad, position="middle")
record(pad, case.id, run_and_grade(ctx))

# 三条读法:
# 1) 成功率随 pad 单调下降 → 腐烂确认,去做 03 到 05 篇的治理
# 2) 只有某几类任务下降 → 对照 2.1,多半是"需要自己建立联系"的那类
# 3) 完全不下降 → 你的任务对长度不敏感,别在这一层花时间,去看别的瓶颈

第 3 种结果是真实存在的,而且先测出来能省下大量白做的工作。上下文工程和任何优化一样,先确认瓶颈在这里,再动手。

六、小结

  • "窗口够大就多塞点"不成立:18 个模型的控制变量实验显示,只把输入拉长,表现就会下降,连复述任务也一样
  • 长度惩罚不均匀:需要模型自己建立联系的任务比字面检索敏感得多
  • 单个干扰项就会拉低表现,所以召回条数不是越多越好;"相关但不是答案"是最有害的那种内容
  • 打乱草堆反而更好,说明结构和长度一样重要 —— 这是"上下文工程"这个说法成立的根据
  • 位置效应是 U 型:开头和结尾好,中间容易被丢
  • 是梯度不是悬崖,所以上下文管理从第一轮就该做,不是窗口满了才做
  • 动手之前先在自己的任务上跑一遍灌水实验,确认瓶颈真的在这儿

下一篇:03 - 压缩与裁剪,第一类手段 —— 把已经在上下文里的东西砍掉。

← 回到 专题索引